﻿using CAPlugin.Implement;
using CAPlugin.Interface;
using HBCA_SOFSEALLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.IO;
using SVS_S_SDK_COMLib;
using CAPlugin.Util;

namespace CAPlugin
{
    public class Program
    {
        private static IServer server;
        private static IClient client;
        private static CSVS_S_SDK tssSDK;
        private static SealClass sealSdk;
        private static string hash_method;

        /// <summary>
        /// 入口
        /// </summary>
        /// <param name="args"></param>
        [STAThread]
        static void Main(string[] args)
        {
            string errMsg = string.Empty;
            // 服务器初始化
            if (!Init(out errMsg))
            {
#if DEBUG
                Console.Error.WriteLine(errMsg);
                Console.WriteLine("点击任何按键退出....");
                Console.Read();
#endif
                return;
            }
            var actionName = args.FirstOrDefault()?.ToLowerInvariant(); // 操作名
            string[] actionPrams = args.Skip(1).ToArray();
            switch (actionName)
            {
                case "read":
                    ShowLoginForm(actionName,actionPrams);
                    break;

                case "bind":
                    ShowLoginForm(actionName,actionPrams);
                    break;

                case "sign":
                    Sign(actionPrams);
                    break;

                case "verify":
                    Verify(actionPrams);
                    break;

                default:
#if DEBUG
                    Console.Error.WriteLine(actionName+"不是合法操作名称！");
                    Console.WriteLine("按任意键退出。");
                    Console.Read();
#endif
                    break;
            }
        }

        /// <summary>
        /// 服务器初始化
        /// </summary>
        /// <returns></returns>
        static bool Init(out string errMsg)
        {
            server = new Server();
            client = new Client();
            tssSDK = server.TssSDK;
            hash_method = ConfigurationManager.AppSettings["hash_method"].ToString();
            bool isInit = false;
            if (!server.ServerInit(out errMsg))
                {
                    return isInit;
                }
                sealSdk = new SealClass();
                isInit = true;
#if DEBUG
            Console.WriteLine("所有服务器初始化成功！");
#endif
            return isInit;
        }

        /// <summary>
        /// 打开窗体
        /// </summary>
        static void ShowLoginForm(string actionName,string[] actionPrams)
        {
            var loginForm = new LoginForm();
            loginForm.OutFile = actionPrams.FirstOrDefault();
            loginForm.Client = client;
            loginForm.TopMost = true; // 显示在所有应用最上方
            loginForm.StartPosition = FormStartPosition.CenterScreen;
            loginForm.Server = server;
            loginForm.Seal = sealSdk;
            if (actionName == "read") // ca登录 返回序列号
            {
                loginForm.ActionName = "read";
            }
            else // "bind"   ca 绑定，返回图片、序列号
            {
                loginForm.ActionName = "bind";
            }
            loginForm.ShowDialog();
            return;
        }

        /// <summary>
        /// 签名
        /// </summary>
        /// <param name="certId"></param>
        /// <param name="inData">待签名MD5</param>
        /// <param name="outData"></param>
        /// <returns></returns>
        static void Sign(string[] actionPrams)
        {
#if DEBUG
            Console.WriteLine("签名操作开始");
#endif
            try
            {
#if DEBUG
                if (actionPrams.Length < 3)
                {
                    throw new Exception("命令参数数量不够！");
                }
                else
                {
                    Console.WriteLine("参数数量正常");
                }
#endif
                string currCertId = actionPrams[0];
                string inData =actionPrams[1]; // 获取摘要
                string fileName = actionPrams[2];

                // 验证绑定证书
                validate:
                if (!client.GetUserList().Contains(currCertId))
                {
                    DialogResult result = MessageBox.Show("请插入用户绑定的UsbKey！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    // 检查返回值
                    if (result == DialogResult.OK)
                    {
                        goto validate;
                    }
                    else if (result == DialogResult.Cancel)
                    {
                        return;
                    }
                }
                string password = Encrypt.DecryptString(File.ReadAllText("Pin.txt"));
#if DEBUG 
                Console.WriteLine("PIN："+password);
#endif
                int res= client.Login(currCertId, password);
#if DEBUG
                if (res != 0)
                {
                    Console.WriteLine("login缓存成功！");
                }
                else
                {
                    Console.WriteLine("login缓存失败，Pin可能不正确");
                }
#endif
                if (client.SetHashMethod(hash_method) != 0)
                {
                    throw new Exception("设置hash_method 失败！");
                }
                else
                {
#if DEBUG
                    Console.WriteLine("待签名数据摘要生成成功！");
#endif
                }

                if (client.SetP7SignMode(1) != 0)
                {
                    throw new Exception("client 将P7签名模式设置为 detach 失败");
                }
                else
                {
#if DEBUG
                    Console.WriteLine("client P7签名模式已设置为:Detach ！");
#endif
                }

                string detachSinData = client.SignDataByP7(currCertId, inData);

                if (string.IsNullOrEmpty(detachSinData))
                {
                    throw new Exception("client P7签名失败！ 返回："+ detachSinData);
                }
                else
                {
#if DEBUG
                    Console.WriteLine("P7签名成功，已生成签名值！ :"+ detachSinData);
#endif
                }

                //　服务端验签
                int iRet = -1;
                if (server.SetP7SignMode(1) != 0)
                {
                    throw new Exception("server P7签名模式设置为Detach失败！");
                }
                else
                {
#if DEBUG
                    Console.WriteLine("Server P7签名 模式已设置为Detach！");
#endif
                }
                iRet = server.VerifyDetachSignedData(detachSinData, inData);

                if (iRet != 0)
                {
                    throw new Exception("Server 验签失败");
                }
                else
                {
#if DEBUG
                    Console.WriteLine("Server 端验签成功！");
#endif
                }
                
                // 时间戳
                string timeStamp = tssSDK.SOF_CreateTimeStampResponse(detachSinData);
                if (String.IsNullOrEmpty(timeStamp))
                {
                    throw new Exception("时间戳生成失败！");
                }
                else
                {
#if DEBUG
                    Console.WriteLine("时间戳为：" + timeStamp);
#endif
                }

                string toFIle = timeStamp + "\r\n" + detachSinData;

                try
                {
                    using (StreamWriter writer = new StreamWriter(fileName,false,Encoding.UTF8))
                    {
                        writer.Write(toFIle);
#if DEBUG
                        Console.WriteLine("签名结果、时间戳已写入文件:"+fileName);
#endif
                    }
                }
                catch (Exception e)
                {
                    throw new Exception("写入文件错误：" + e.Message);
                }
            }
            catch (Exception e)
            {
                string caErrMsg = string.Empty;
                string clientErr = client.GetErrorMsg();
                string serverErr = server.GetErrorMsg();
                caErrMsg = string.IsNullOrEmpty(clientErr) ? "client-"+ caErrMsg : caErrMsg +"client-"+ clientErr;
                caErrMsg = string.IsNullOrEmpty(serverErr) ? "server-"+ caErrMsg: caErrMsg+ "server-"+ serverErr;

                string errMsg = string.Empty;
                errMsg = string.IsNullOrEmpty(caErrMsg) ? errMsg : e.Message + "\r\n ca接口错误信息：" + caErrMsg;

                DialogResult result= MessageBox.Show(errMsg, "提示", MessageBoxButtons.OK);
            }
            return;
        }


        /// <summary>
        /// 验签
        /// </summary>
        /// <param name="certId"></param>
        /// <param name="inData"></param>
        /// <param name="signedValue"></param>
        static void Verify(string[] actionPrams)
        {
            try
            {
                string pStr = string.Empty;
                foreach (string p in actionPrams)
                {
                    pStr += (p + ",");
                }
#if DEBUG
                Console.WriteLine("参数列表：" + actionPrams.ToString());
                Console.WriteLine("参数数量：" + actionPrams.Length);
#endif
                if (actionPrams.Length < 2)
                {
                    throw new Exception("命令参数数量不够！");
                }
                string currCertId = actionPrams[0];
                string filePath = actionPrams[1];
#if DEBUG
                Console.WriteLine("输入、输出文件路径：");
#endif
//                // 验证绑定证书
//                if (client.ValidateCert(currCertId) != 0)
//                {
//#if DEBUG
//                    Console.WriteLine("绑定的证书未登录！");
//#endif
//                    var loginForm = new LoginForm();
//                    loginForm.Client = client;
//                    loginForm.Server = server;
//                    loginForm.Seal = sealSdk;
//                    loginForm.DefaultCert = currCertId;
//                    loginForm.ActionName = "unLoginSign";
//                    DialogResult result = loginForm.ShowDialog();
//                    if (result == DialogResult.Cancel)
//                    {
//                        return;
//                    }
//                }
//                else
//                {
//#if DEBUG
//                    Console.WriteLine("绑定的证书已经登录！");
//#endif
//                }
                

                string inData = string.Empty;  // 待验签
                string p7SignedData = string.Empty;
                string timeStamp = string.Empty;
                if (!File.Exists(filePath))
                {
                    throw new Exception("fileName值参数指向的文件不存在！");
                }
                else
                {
                    try
                    {
                        string[] inFileStrings = File.ReadAllText(actionPrams[1]).Split(new string[] { "\r\n" }, StringSplitOptions.None);
                        if (inFileStrings.Length != 3)
                        {
                            throw new Exception("输入文件：" + actionPrams[1] + "内容不正确！ 行数：" + inFileStrings.Length);
                        }
                        else
                        {
#if DEBUG
                            Console.WriteLine("输入文件：" +actionPrams[1] + "行数正常！ 行数：" + inFileStrings.Length);
#endif
                            inData = inFileStrings[0];
                            timeStamp = inFileStrings[1];
                            p7SignedData = inFileStrings[2];
                        }
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                if (server.SetP7SignMode(1) != 0)// P7 Detach模式
                {
                    throw new Exception("server 将P7签名模式设置为Detach失败！");
                }
                else
                {
#if DEBUG
                    Console.WriteLine("Server端，P7签名模式已设置为Detach!");
#endif
                }

                if (server.VerifyDetachSignedData(p7SignedData, inData) != 0)
                {
                    throw new Exception("P7验签失败");
                }
                else
                {
#if DEBUG
                    Console.WriteLine("Server端，验签成功！");
#endif
                }

                //if (string.IsNullOrEmpty(tssSDK.SOF_VerifyTimeStamp(timeStamp)))
                //{
                //    throw new Exception("时间戳验证失败！");
                //}
                //else
                //{
                //    Console.WriteLine("时间戳验证成功！");
                //}

                MessageBox.Show("签名验证成功！","提示",MessageBoxButtons.OK,MessageBoxIcon.Information,MessageBoxDefaultButton.Button1,MessageBoxOptions.ServiceNotification);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message+"\r\n tssSdk-"+tssSDK.SOF_GetErrorMsg(), "错误");
            }
            return;
        }
    }
}
